/*
 License
 
 Copyright © 2012 Kevin Kimmich
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights to 
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 the Software, and to permit persons to whom the Software is furnished to do so, 
 subject to the following conditions:
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 @file
 Types that are used by libkuato.
 */

#ifndef		_libkuato_types_h
#define 	_libkuato_types_h

#ifdef __cplusplus
extern "C" {
#endif

//Lump all system dependencies in one place
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdarg.h>
#include <memory.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <syslog.h>
#include <pthread.h>
#include <setjmp.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <regex.h>
#include <netinet/in.h> 
#include <netinet/tcp.h> 
#include <semaphore.h>
#include <pthread.h>
#include <sys/uio.h>
#ifdef ENABLE_LIBXML
#include <libxml/parser.h>
#include <libxml/xpath.h>
#endif
#ifdef ENABLE_SSL
#include <openssl/ssl.h>
#include <openssl/rand.h>
#endif
#include <uuid/uuid.h>
	
#include "crcore.h"
#include "libkuato_config.h"
	
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
	
#define SUCCESS (0)
#define FOREVER (0xFFFFFFFF)
	
	extern int default_timeout;
	
	typedef uint32_t ipv4;
	
	struct connection_context;
	typedef struct connection_context connection_context;
	struct domain_object;
	typedef struct domain_object domain_object;
	struct http_server_object;
	typedef struct http_server_object http_server_object;
	
	/**
	 method type.
	 */
	typedef enum method_type { INVALID=0,GET,POST,HEAD,PUT,DELETE,CONNECT,TRACE,OPTIONS,PATCH } method_type;
	typedef enum context_type { CLIENT, LISTENER, SSL_LISTENER, SERVER } context_type;
	
	/**
	 A URI. Check out: http://www.ietf.org/rfc/rfc3986.txt
	 */
	typedef struct URI
	{
		char* scheme; /*!< the scheme, e.g. http*/
		char* authority;/*!< the authority, e.g. www.cnn.com*/
		char* path;/*!<The path /a/b/c.html*/
		char* query;/*!<The query follows the ?*/
		char* fragment;/*!<The fragment follows the #*/
	} URI;
	
	/**
	 A structure representing a domain. One http server can host
	 multiple domains.
	 */
	struct domain_object
	{
		list_node_t node; /*!< the  list node */
		http_server_object* http_srv; /*!< the server object that owns this domain */
		void* priv; /*!< domain object private user data. */
		const char* root; /*!< The root of this domain */
		const char* default_file; /*!< The default file of this domain */
		const char* domain_name; /*!< The name of this domain */
		const char** aliases; /*!< It's aliases */
		list_t match_rules; /*!< The match rules attached to this domain */
	};
	

	/**
	 * A structure that represents a bound listener connection
	 */
	typedef struct
	{
		list_node_t node; /*!< the list node*/
		connection_context* ctx; /*!< The listener context */
		struct sockaddr_in addr; /*!< The socket address this listener was bound to */
	} server_connection_t;
	
	/**
	 A structure representing an HTTP server. Which is a binding to one or more TCP listener sockets.
	 */
	struct http_server_object
	{
		void* priv; /*!< Pointer to private application data */
		list_t server_connections; /*!< list of listening connections */
		list_t domains; /*!< list of domains */
		SSL_CTX* sslctx; /*!< an SSL context */
	};
	
	/**
	 The request structure.
	 */
	typedef struct request
	{
		char* header; /*!< The unparsed header */
		stream s; /*!< Scratch stream. */
		stream body; /*!< The request body. */
		
		const char* method; /*!< The request method. */
		const char* url; /*!< The request url. */
		const char* version; /*!< The request version. */
		
		hash_string_t dict;/*!< the header fields in a dictionary form. */
		uint32_t content_length; /*!< The length of the body */
		int32_t chunk_length; /*!< The length of a chunk when it's a chunked transfer */
		
		stream chunk_body; /*!< The body of a chunked transfer */
		
		URI uri; /*!< The parsed URL as a URI */
		method_type mtype; /*!< The method type as a enum value */
		result_code status; /*!< The finished result code */
	} request;
	
	/**
	 The response structure.
	 */
	typedef struct response
	{
		char* header; /*!< The unparsed header */
		stream s; /*!< Scratch stream */
		stream body; /*!< The completed request body. */
		
		const char* version; /*!< The response version */
		const char* status_code; /*!< The response status code string */
		const char* reason_phrase; /*!< The response reason phrase */
		
		hash_string_t dict; /*!< The response header dictionary */
		uint32_t content_length; /*!< The response body's content length as reported by the server. */
		int32_t chunk_length; /*!< The response's body chunk length for chunked transfers */
		
		stream chunk_body; /*!< The chunk body. */
	} response;

	/**
	 * States of request processing.
	 */
	typedef enum method_status 
	{ 
		METHOD_WAIT_HEADER=0,
		METHOD_HEADER_ERROR,
		METHOD_WAIT_BODY,
		METHOD_REQUEST_COMPLETE,
		METHOD_BODY_ERROR,
		METHOD_RUNNING,
		METHOD_COMPLETE,
		METHOD_SOCKET_CLOSED
	} method_status;
	
	struct method;
	typedef struct method method;
	struct chunked_handler;
	
	/**
	 The handler type.
	 */
	typedef enum
	{
		discrete=0, /*!< Processes the response as a discrete response. */
		chunked=1 /*!< Processes the request as chunked transfer. */
	} handler_t;

	/**
	 * Match rule types
	 */
	typedef enum
	{
		match_null=0, /*!<Match nothing*/
		match_any,/*!<Matches everything*/
		match_address,/*!<Match the address, specified as a string "ip.ip.ip.ip/nm.nm.nm.nm"*/
		match_method,/*!<Match the method CSV list of methods "GET,PUT"*/
		match_path,/*!<Regular expression matching the path*/
		match_context, /*!<Matches the server context*/
		invert_match_address,/*!<Doesn't match the address*/
		invert_match_method,/*!<Doesn't match the method*/
		invert_match_path,/*!<Doesn't match the path*/
		invert_match_context/*!<Doesn't match the context*/
	} match_type_t;

	/**
	 * How the expressions are combined
	 */
	typedef enum
	{
		match_AND=0,/*!<Combine with logical AND*/
		match_OR/*!<Combine with logical OR*/
	} match_combination_t;

	/**
	 * The maximum number of comparisons
	 */
	#define MAX_COMPARISONS (4)

	/**
	 * The expression components
	 */
	typedef struct
	{
		match_type_t type[MAX_COMPARISONS];
		match_combination_t combination[MAX_COMPARISONS-1];
		
		union{
			const char* address[MAX_COMPARISONS];
			const char* method[MAX_COMPARISONS];
			const char* path[MAX_COMPARISONS];
			const connection_context* ctx[MAX_COMPARISONS];
			void* value[MAX_COMPARISONS];
		};
		uint32_t addr[MAX_COMPARISONS];
		uint32_t nmask[MAX_COMPARISONS];
		regex_t path_regex[MAX_COMPARISONS];
	} match_expression_t;
	
	/**
	 * A match rule gets compiled into this structure
	 */
	typedef struct
	{
		list_node_t node;
		handler_t htype; /*!< The handler type. */
		int count; /*!< The count of expressions. */
		match_expression_t expression; /*!< The expression */		
		void(*handle_request)(method*); /*!< The open method for this rule. */
	} http_match_rule_t;
	
	/**
	 A method--used for requests and responses.
	 */
	struct method
	{
		list_node_t node;
		method_status status;/*!<The status of the method while it's being processed*/
		
		http_server_object* http_srv;/*!<The server object--only for methods received by the server*/
		domain_object* d;/*!<The domain object--only for methods received by the server*/
		connection_context* ctx;/*!<The context for this method*/
		http_match_rule_t* rule;/*!<The rule which was matched for the server method*/
		
		context_type type;/*!<CLIENT or SERVER*/
		request req;/*!<When a server method is called, this structure contains request data. For a client method, this is used for the request data.*/
		response resp;/*!<The response data that will be sent back to the client*/ 

#ifdef ENABLE_LIBXML
		xmlDocPtr request_doc;/*!<The XML body of a request*/
		xmlDocPtr response_doc;/*!<The XML body of a response*/
#endif		
		//streaming stuff
		stream server_input_stream;
	};
	
	
	#ifdef ENABLE_LIBXML
	/**
	 access the method's XML document.
	 @param m the method.
	 */
	static __inline__ xmlDocPtr method_get_doc(method* m){ return m->response_doc; }
	#endif

	
	#ifdef ENABLE_LIBXML
	/**
	 Parse any XML response.
	 */
	#define PARSE_RESPONSE (0x00000001)
	#endif
	
	/**
	 A context for a TCP socket.
	 */
	struct connection_context
	{
		context_type type;
		int result;
		int fd;
		struct sockaddr_in addr;
		struct timeval last_received_time;
		struct timeval last_sent_time;
		int32_t bytes_sent;
		int32_t bytes_received;
		uint32_t read_buffer_size;
		stream read_stream;
		stream write_stream;
		
		http_server_object* http_srv;
		connection_context* srvctx;
		list_t methods;
		method* m;
		
		core_thread_t* thread_id;

#ifdef ENABLE_SSL
		//ssl stuff
		SSL *ssl;
#endif
	};
	
#ifdef __cplusplus
}
#endif


#endif
